<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>nextTick原理</title>
</head>

<body>
  <div>
    <div id="el"></div>
    <button id="btn">count++</button>

    <script>
      const el = document.querySelector('#el');
      const btn = document.querySelector('#btn');

      let num = 0;
      let activeEffect = null; // 当前的副作用函数
      let effectSet = new Set(); // 存储副作用函数的集合

      let tasks = new Set(); // 存储任务的集合
      function runTask() { // 执行任务
        Promise.resolve().then(() => { // 微任务
          tasks.forEach(task => task()); // 执行所有任务
          tasks.clear(); // 清空任务集合
        });
      }


      function effect(fn) {
        activeEffect = fn; // 存储副作用函数
        fn(); // 执行副作用函数
        activeEffect = null; // 副作用函数执行完毕，重置activeEffect    
      }

      const count = {
        _val: 0, // 存储原始值
        get value() { // 读取value属性时，收集副作用函数
          if (activeEffect) {
            effectSet.add(activeEffect); // 收集副作用函数
          }
          return this._val; // 返回原始值
        },
        set value(newVal) { // 修改value属性时，触发副作用函数
          this._val = newVal; // 修改原始值
          effectSet.forEach(fn => tasks.add(fn));
          console.log("🚀 ~ Promise.resolve ~ tasks:", tasks)
          runTask(); // 执行任务
        },
      }

      effect(() => { // 副作用函数
        console.log("🚀 ~ effect ~ effect:", num)
        num++;
        el.innerText = count.value; // 读取count.value属性，收集副作用函数
      });

      // nextTick 相当于将你的事件添加到微任务，等待更新任务的微任务完成后才执行你的时间，这样就能拿到更新后的东西
      function nextTick(fn) {
        Promise.resolve().then(fn); // 微任务
      }

      btn.onclick = () => { // 点击按钮时，修改count.value属性，触发副作用函数
        count.value++;
        count.value++;
        nextTick(() => { // 注册任务
          console.log("🚀 ~ btn.onclick ~ nextTick:", el.innerText)
        })
      }
    </script>
  </div>
</body>

</html>